﻿using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// WebSocket 打印客户端
/// </summary>
public class WssPrintClient : IDisposable
{
    /// <summary>
    /// 连接状态改变事件
    /// </summary>
    public event Action<bool> OnConnectionStateChanged;

    /// <summary>
    /// 接收消息事件
    /// </summary>
    public event Action<string> OnMessageReceived;

    /// <summary>
    /// 错误发生事件
    /// </summary>
    public event Action<Exception> OnErrorOccurred;

    private ClientWebSocket _webSocket;
    private CancellationTokenSource _cancellationTokenSource;
    private Uri _serverUri;
    private bool _isDisposed;
    private bool _isConnected;

    /// <summary>
    /// 是否已连接
    /// </summary>
    public bool IsConnected => _isConnected;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="serverUrl">WebSocket 服务器地址</param>
    public WssPrintClient(string serverUrl)
    {
        if (string.IsNullOrEmpty(serverUrl))
            throw new ArgumentNullException(nameof(serverUrl));

        if (!Uri.TryCreate(serverUrl, UriKind.Absolute, out var uri))
            throw new ArgumentException("无效的服务器地址", nameof(serverUrl));

        if (uri.Scheme != "ws" && uri.Scheme != "wss")
            throw new ArgumentException("地址必须使用 ws 或 wss 协议", nameof(serverUrl));

        _serverUri = uri;
        _webSocket = new ClientWebSocket();
    }

    /// <summary>
    /// 连接到服务器
    /// </summary>
    /// <returns>是否连接成功</returns>
    public async Task<bool> ConnectAsync()
    {
        try
        {
            if (_isConnected)
                return true;

            _cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2));
            _webSocket = new ClientWebSocket();

            await _webSocket.ConnectAsync(_serverUri, _cancellationTokenSource.Token);

            _isConnected = true;
            OnConnectionStateChanged?.Invoke(true);

            // 开始监听消息
            _ = ListenForMessagesAsync();

            return true;
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
            return false;
        }
    }

    /// <summary>
    /// 断开与服务器的连接
    /// </summary>
    public async Task DisconnectAsync()
    {
        if (!_isConnected)
            return;

        try
        {
            _cancellationTokenSource?.Cancel();
            await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "正常关闭", CancellationToken.None);
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
        }
        finally
        {
            _isConnected = false;
            OnConnectionStateChanged?.Invoke(false);
            CleanupResources();
        }
    }

    /// <summary>
    /// 发送文本消息（异步）
    /// </summary>
    /// <param name="message">要发送的消息</param>
    public async Task SendMessageAsync(string message)
    {
        if (!_isConnected)
            throw new InvalidOperationException("未连接到服务器");

        if (string.IsNullOrEmpty(message))
            throw new ArgumentNullException(nameof(message));

        try
        {
            var bytes = Encoding.UTF8.GetBytes(message);
            await _webSocket.SendAsync(
                new ArraySegment<byte>(bytes),
                WebSocketMessageType.Text,
                true,
                _cancellationTokenSource.Token);
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
            // 如果发送失败，尝试重新连接
            await HandleConnectionError();
        }
    }

    /// <summary>
    /// 发送文本消息（同步）
    /// </summary>
    /// <param name="message">要发送的消息</param>
    public void Send(string message)
    {
        // 同步等待异步操作完成
        SendMessageAsync(message).GetAwaiter().GetResult();
    }

    /// <summary>
    /// 监听消息
    /// </summary>
    private async Task ListenForMessagesAsync()
    {
        var buffer = new byte[1024 * 4]; // 4KB 缓冲区

        try
        {
            while (_isConnected && !_cancellationTokenSource.Token.IsCancellationRequested)
            {
                var result = await _webSocket.ReceiveAsync(
                    new ArraySegment<byte>(buffer),
                    _cancellationTokenSource.Token);

                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await DisconnectAsync();
                    break;
                }

                if (result.MessageType == WebSocketMessageType.Text)
                {
                    var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
                    ReadText = message;
                    OnMessageReceived?.Invoke(message);
                }
            }
        }
        catch (OperationCanceledException)
        {
            // 预期的取消操作，不视为错误
        }
        catch (Exception ex)
        {
            OnErrorOccurred?.Invoke(ex);
            await HandleConnectionError();
        }
    }

    /// <summary>
    /// 处理连接错误
    /// </summary>
    private async Task HandleConnectionError()
    {
        if (_isConnected)
        {
            _isConnected = false;
            OnConnectionStateChanged?.Invoke(false);

            // 尝试重新连接
            await Task.Delay(3000); // 等待3秒后重试
            await ConnectAsync();
        }
    }

    /// <summary>
    /// 清理资源
    /// </summary>
    private void CleanupResources()
    {
        _webSocket?.Dispose();
        _webSocket = null;

        _cancellationTokenSource?.Dispose();
        _cancellationTokenSource = null;
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// 释放资源
    /// </summary>
    /// <param name="disposing">是否手动释放</param>
    protected virtual void Dispose(bool disposing)
    {
        if (_isDisposed)
            return;

        if (disposing)
        {
            // 释放托管资源
            _ = DisconnectAsync();
        }

        _isDisposed = true;
    }
    public string ReadText = string.Empty;
    public string PrintWaybill(string waybillNo)
    {
        ReadText = string.Empty;
        var tempContent = string.Empty;
        try
        {
            Send(waybillNo);
            return "ok";
        }
        catch (Exception)
        {
            return IsConnected ? "" : "DisConnected";
        }
    }

    /// <summary>
    /// 析构函数
    /// </summary>
    ~WssPrintClient()
    {
        Dispose(false);
    }
}
